home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
amiga-magazin-pd
/
11-94-6
/
xass 64
/
xass 1.0
/
anleitung
next >
Wrap
Text File
|
1995-03-09
|
59KB
|
989 lines
Sind Sie stolzer Besitzer sowohl eines Commodore 64 als auch eines
Commodore Amiga? Programmieren Sie noch immer professionelle Software in
Assembler auf dem guten alten C64? Dann werden Sie wahrscheinlich oft, wenn
Sie sich mit der, im Vergleich zum Amiga wohl als vorsintflutlich zu
bezeichnenden Programmierumgebung herumschlagen mußten, neidisch zu Ihrem
Amiga geblickt haben. Von diesem mit tollen Editoren, grafischer
Benutzeroberfläche, Windowing, Multitasking und hoher Geschwindigkeit ver-
wöhnt, bleibt Ihnen trotzdem nichts anderes übrig, als mit dem kleinen
Speicher und der langsamen Floppy zusätzlich zum unkomfortablen Basic-
editor, der meist benutzt werden muß, auszukommen. Welche Probleme sich
hier ergeben, kann sich wahrscheinlich jeder lebhaft vorstellen.
Es dürfte bereits klar sein, auf was ich hinaus will: Es müßte einfach
eine Möglichkeit geben, dem Amiga die Maschinensprache des C64 beizubringen
um dann auf diesem mit all seinen Möglichkeiten Programme für den C64
erstellen zu können - auf komfortablere und einfachere Weise, als es mit
dem C64 selbst je möglich wäre. Schließlich müssten sich diese Programme
dann noch zum C64 übertragen lassen. Am Ende dieses Gedankenganges (und
noch vieler weiterer kleiner Einfälle) steht das, was Sie nun vor sich
liegen haben: Das 6510-Developers-Packet.
Obwohl die Idee, auf größeren Rechnern Programme für kleinere Rechner zu
entwickeln, nicht neu ist, wurde sie auf dem Amiga für den doch immer noch
recht beliebten und für sein Alter von nunmehr 10 Jahren noch erstaunlich
leistungsfähigen C64 in dieser Weise (so weit ich weiß) noch nie reali-
siert. Das 6510-Developers-Packet beinhaltet deswegen alle Komponenten,
die nötig sind, um einerseits dem Amiga das nötige Wissen zu geben, mit
6510-Assembler etwas anfangen zu können und andererseits die Übertragung
zum C64 zu realisieren. Der im Paket enthaltene 6510-Cross-Makroassembler
"CrossAss V1.0" ist dafür zuständig, den Amiga mit 6510-Assembler, für
den er normalerweise kein Verständnis hat, vertraut zu machen. "CrossAss
V1.0" kann 6510-Assemblerprogramme, die mit einem beliebigen Textedi-
tor Ihrer Wahl erstellt wurden, "interpretieren" und die darin enthaltenen
6510-Mnemonics in Opcodes umwandeln (=assemblieren). So entsteht noch auf
dem Amiga ein auf dem C64 lauffähiges Maschinensprachprogramm, welches
nur noch übertragen werden muß.
Da das Programm im Speicher des Amiga praktisch bereits genauso
vorliegt, wie es der C64 später brauchen wird, beschränkt sich der Teil der
Software, die für den C64 bestimmt ist, auf Routinen, die den Empfang der
Daten realisieren. Prinzipiell gibt es zur Übertragung der Daten vom Amiga
zum C64 zwei einfache Möglichkeiten, nämlich die serielle Übertragung per
RS232-Schnittstelle oder die parallele Übertragung vom Parallelport des
Amiga zum Userport des C64. Die erste Möglichkeit hat zwar den Vorteil,
daß Übertragungsroutinen bereits in den Betriebssystemen sowohl des Amiga
als auch des C64 enthalten sind, jedoch aber auch einige entscheidende
Nachteile. Zunächst besitzt der C64 zwar RS232-Routinen, aber keine solche
Schnittstelle. Diese müßte über relativ komplizierte Hardwareerweiterungen
nachgerüstet werden. Außerdem ist die serielle Schnittstelle aufgrund der
Notwendigkeit des Taktens der Übertragung mit auf beiden Computern
übereinstimmenden Übertragungsraten (BAUD/BPS-Raten) eine heikle,
umständliche und nicht gerade einfache Sache. Die zweite Möglichkeit hat
nur den Nachteil fehlender Betriebssystemunterstützung durch den C64. Die
Vorteile sind jedoch immens: Durch Übertragung von jeweils 8 Bit und die
selbstständige Geschwindigkeitsanpassung (Handshaking) tritt keines der
Probleme der seriellen Übertragung auf und die Geschwindigkeit erreicht
immer das Maximum. Da der C64 nur empfängt, aber selbst nicht sendet,
liegt nichts näher, als den C64 wie einen Drucker am parallelen Port des
Amiga anzusprechen, was durch das Betriebssystem des Amiga ja sowieso
unterstützt wird.
Das Kabel an sich ist entsprechend sehr einfach aufgebaut. Trotzdem
sollte der Nachbau sorgfältig erfolgen, da falsch angelötete Leitungen die
Zerstörung eines oder beider Computer zur Folge haben können. Markieren
Sie sich auch die Oberseite des nicht verdrehsicheren
C64-Userport-Steckers! Außerdem darf das Kabel nie eingesteckt werden,
wenn die Rechner gerade in Betrieb sind. Sind beide Rechner erfolgreich
mit dem Kabel verbunden, so kann nach vollendeter Assemblierung die
Übertragung beginnen, wobei hier zwei verschiedene Empfangsroutinen auf dem
C64 dafür sorgen, daß die übertragenen Daten entweder direkt auf Disk
("Transfer") oder im RAM des C64 ("TransRAM") landen. Dort können sie dann
weiterverwendet werden.
Für die Funktionsweise des Assemblers wurde die auf dem C64 übliche
2-Pass-Assemblierung verwendet. Das bedeutet, daß der Assembler den
Quelltext zweimal durchläuft, wobei er in Pass 1 nur die Labeldefinitionen
übernimmt. In Pass 2 erfolgt dann die eigentliche Assemblierung des
Quelltextes mit Zugriff auf alle Labels. Auf daraus folgende Konsequenzen
wird noch öfter in dieser Anleitung eingegangen werden.
Wie bereits erwähnt, erfolgt die Eingabe der 6510-Assembler-Programme
mit einem Texteditor Ihrer Wahl. Das kann entweder Ihr Lieblingstexteditor
oder Ihre Lieblingstextverarbeitung (im ASCII-Modus) sein, oder auch die
Editoren "Ed" der Workbench- bzw. "MicroEmacs" der Extras-Diskette. Damit
CrossAss V1.0 Ihren Quelltext aber auch wirklich verstehen kann, müssen Sie
sich an einige Regeln halten. Wie Sie sehen werden, ist CrossAss hier aber
äußerst großzügig. Der grundsätzliche Aufbau einer Zeile sieht in etwa so
aus:
LABEL ANWEISUNG OPERAND,OPERAND,OPERAND... ;KOMMENTAR
"In etwa" nur deshalb, weil eine Quelltextzeile nicht immer exakt obige
Gestalt annimmt. Ganz im Gegenteil kann auch der Fall auftreten, daß keine
der obigen Komponenten tatsächlich vorhanden sind. Wichtig ist zunächst
nur, daß sowohl Label als auch Anweisung (wird alles noch erklärt) und der
erste Operand durch mindestens ein Leerzeichen getrennt werden müssen.
Sollten mehrere Operanden folgen, so werden diese durch Kommata getrennt
angegeben. Ein eventuell angefügter Kommentar wird durch ein Semikolon ";"
eingeleitet und endet am Zeilenende. Ist das erste Nichtleerzeichen der
Zeile sofort ein Semikolon, so wird entsprechend die ganze Zeile als
Kommentarszeile überlesen. Ist die Zeile völlig leer (eben der obige Fall,
daß keine der Komponenten der Zeile vorhanden sind), so wird entsprechend
auch nichts assembliert. Sie können also zur Strukturierung Ihres Pro-
gramms einfach Leerzeilen einfügen, was zur Übersichtlichkeit beiträgt.
Da ich vorraussetze, daß Sie bereits auf dem C64 mit anderen Assemblern
gearbeitet haben, wird Ihnen dieser Zeilenaufbau nicht fremd sein und
entsprechend dürfte die Verwendung eines Labels am Zeilenanfang zur
Zuweisung des aktuellen Programmcounters ebenfalls bekannt sein, da gerade
diese Möglichkeit ja die Flexibilität eines Assemblers ausmacht. Es ist
aber natürlich keine Pflicht, ein Label am Anfang der Zeile zu definieren.
Unter Anweisung versteht sich entweder ein Mnemonic, ein Pseudo-Opcode
oder ein Makroname. All diese Begriffe sind Ihnen sicherlich nicht
unbekannt, so daß die Begriffserläuterungen unten genügen sollte. Damit
der Rahmen dieses Artikels nicht gesprengt wird, kann hier natürlich nur
auf CrossAss V1.0-spezifische Dinge genauer eingegangen werden.
Beachten Sie beim Erstellen des Quelltextes, daß grundsätzlich nur eine
Anweisung pro Zeile stehen darf. Die Definition eines Labels am
Zeilenanfang und die Verwendung eines Kommentars ist, wie bereits gesagt,
optional. Mit Kommentaren sollten Sie aber aus Selbstzweck nicht sparen,
sofern Sie sich später noch in Ihrem Programm auskennen wollen.
Die Anzahl der auf die Anweisung folgenden Operanden hängt von der
Anweisung selbst ab. Während auf Mnemonics grundsätzlich nur ein Operand
folgt, der unter anderem die Adressierungsart bestimmt, können auf Makros,
je nach Definition, und auf Pseudo-Opcodes, je nach "Natur", auch zwei oder
mehrere Operanden folgen. Es wird zwischen drei Arten von Operanden
unterschieden:
- Terme
- Mnemonic-Operanden (enthalten Terme)
- Texte
CrossAss V1.0 bietet die Möglichkeit, überall dort, wo Werte assembliert
werden sollen, mathematische Terme zu verarbeiten. Dabei hält sich
CrossAss an die mathematischen Grundregeln (Punkt vor Strich etc.). Terme
können durch die Verwendung von "(", "[", ")" und "]" geklammert werden.
Die in einem Term verwendeten Zahlen können als
- Ziffernfolgen
- Labels
- Makroparameter
- Zeichen
- "*"
auftreten. Ziffernfolgen können dabei in vier verschiedenen Zahlensystemen
verwendet werden, worüber das Vorzeichen der Zahl entscheidet. Dezimal-
zahlen (Basis 10) haben kein Vorzeichen, Hexadezimalzahlen (Basis 16) ein
"$" (Zusatzziffern "a"-"f" bzw. "A"-"F"), Oktalzahlen (Basis 8) ein "&"
und Binärzahlen (Basis 2) ein "%". Bei der Verwendung von Labels werden
diese durch ihre Werte ersetzt. Makroübergabeparameter sind nur innerhalb
von Makroquelltexten verwendbar. Sie werden durch das Vorzeichen "?"
eingeleitet, auf das eine Ziffer zwischen 0 und 9 (einschließlich) folgt,
die die Nummer des Parameters bestimmt (0 = Parameter 1 ... 9 = Parameter
10). Die Verwendung von Zeichen wird durch das Vorzeichen "'" (ALT+ä)
eingeleitet auf welches das zu verwendende Zeichen folgen muß. Dieses
Zeichen wird durch seinen ASCII-Code ersetzt, welcher mit Hilfe der
veränderbaren (wird später erklärt) Konvertierungstabelle angepasst wird.
Die Zahl "*" schließlich ist ein Sonderfall. Sie wird bei der Assem-
blierung durch den aktuellen Programmzähler ersetzt. Vor alle Zahlen, aber
auch vor geklammerte Terme können zusätzlich noch die Vorzeichen "<" und
">" gestellt werden, die CrossAss V1.0 veranlassen, nur das Low- ("<") bzw.
das Highbyte (">") des Wertes zu verwenden. Neben den Grundrechenarten
"+", "-", "*" (Multiplikation) und "/" (Division) kennt CrossAss V1.0 noch
folgende weitere Rechenarten:
"|" ODER-Verknüpfung linker Wert mit rechtem Wert
"&" UND-Verknüpfung linker Wert mit rechtem Wert (nicht zu
verwechseln mit dem Vorzeichen oktaler Zahlen)
"^" EXCLUSIV-ODER Verknüpfung linker Wert mit rechtem Wert
"<" Verschiebung von linkem Wert um rechten Wert Bits nach LINKS
(nicht zu verwechseln mit Vorzeichen "<")
">" Verschiebung von linkem Wert um rechten Wert Bits nach RECHTS
(nicht zu verwechseln mit Vorzeichen ">")
Mnemonic-Operanden können logischerweise nur auf Mnemonics folgen und
enthalten sowohl die Adressierungsart des Mnemonics selbst, als auch einen
zur Adressierungsart gehörenden Wert, wobei dieser je nach Adressierungsart
eine Breite von 8 oder 16 Bit hat. Natürlich kann auch dieser Wert durch
einen Term angegeben werden. Die Angabe der Adressierungsart erfolgt durch
die Standardschreibweisen, die allgemein bekannt sein dürften:
immediate (8 Bit): #Term
absolut (16 Bit): Term
absolut x-indiziert (16 Bit): Term,x
absolut y-indiziert (16 Bit): Term,y
Zeropage (8 Bit): Term
Zeropage x-indiziert (8 Bit): Term,x
Zeropage y-indiziert (8 Bit): Term,y
indiziert indirekt (8 Bit): (Term,x)
indirekt indiziert (8 Bit): (Term),y
relativ (16 Bit): Term
indirekt (16 Bit): (Term)
Akkumulator/implement (8 Bit): kein Operand !
Zu beachten gibt es hier folgendes: Bei den indizierten Adressierungen ist
es egal, ob die Angabe des Indexregister in Groß- oder Kleinschrift
erfolgt. Bei relativer Adressierung wird der 16-Bit-Wert in einen
relativen, vorzeichenbehafteten 8-Bit-Wert umgewandelt, so daß bei
Branchsprüngen eine maximale Reichweite von 126 Byte in Richtung Programm-
anfang bzw. 129 Byte in Richtung Programmende erreicht wird. Bei
indirekten Adressierungen dürfen nur runde Klammern als Adressierungs-
merkmal benutzt werden, eckige Klammern sind der Klammerung von Termen
vorbehalten. Vorsicht ist bei der Unterscheidung zwischen den Zeropage-
und absoluten Adressierungsarten geboten. Hier wird nur durch die
Bitbreite des Wertes entschieden um welche Adressierungsart es sich
handelt. Eine Problem kann sich hierbei nämlich daraus ergeben, daß
CrossAss ein 2-Pass-Assembler ist. Wie bereits erwähnt, beschränkt sich
die Arbeit von CrossAss in Pass 1 ausschließlich auf das Definieren der
Labels. Da für die Definition von Labels am Zeilenanfang aber der
Programmcounter bekannt sein muß, müssen bereits hier alle Adressierungs-
arten richtig erkannt werden. Wird nun eine Adressierung in Abhängigkeit
eines Labels gebracht, das darüber entscheidet, ob es sich um eine
Zeropage- oder um eine absolute Adressierungsart handelt und ist dieses
Label noch nicht bekannt, weil es z.B. später im Quelltext definiert wird,
so nimmt der Assembler an, es handele sich um die absolute
Adressierungsart. Wird dieses Label später jedoch so definiert, daß es
sich in Wahrheit um eine Zeropageadressierung gehandelt hätte, so wird
diese in Pass 2 zwar richtig assembliert, aber es ergibt sich eine
Differenz zwischen den Programmcountern in Pass 1 und Pass 2 was mit
höchster Wahrscheinlichkeit falsche Sprungadressen im Objektcode zur Folge
hat, ohne daß der Assembler hiervor warnen könnte. Sollte also der Fall
gegeben sein, daß eine Zeropageadressierung in Abhängigkeit eines Labels
assembliert werden soll, so muß in diesem Fall unbedingt das Label bereits
vorher im Quelltext definiert worden sein! Möchte man jedoch genau den
entgegengesetzten Fall erreichen, nämlich unbedingt eine absolute Adres-
sierungsart erzwingen (manchmal notwendig bei selbstmodifizierenden
Programmen), so muß vor den gesamten Operanden das Vorzeichen "!" gesetzt
werden.
Die letzte Art eines Operanden tritt ausschließlich bei Pseudo-Opcodes
auf. Es handelt sich um ganze Texte, die z.B. Dateinamen enthalten
können, aber auch dazu bestimmt sein können, in den Objektcode eingefügt zu
werden. In letzterem Fall werden sie wieder mit Hilfe der Konvertierungs-
tabelle angepasst. Ein Text beginnt und endet mit einem Anführungszeichen
("), wobei keines der beiden vergessen werden darf. Texte können ent-
sprechend alle Zeichen, also auch Kommata, enthalten.
Die maximale Anzahl einzelner Operanden beträgt übrigens 32, während die
maximale Länge eines jeden Operanden 80 Zeichen nicht überschreiten darf
(wichtig bei Texten).
Zu Mnemonics und deren Adressierungsarten braucht im Rahmen dieser
Anleitung wohl nichts mehr gesagt werden, da diese entweder bekannt,
oder in jeder Fachliteratur zum 6510 nachzulesen sind. Die Pseudo-Opcodes
von CrossAss müssen jedoch einzeln erläutert werden, da sie sich in vielen
Punkten von denen anderer Assembler unterscheiden und außerdem stark
unterschiedliche Funktionen haben. Zunächst sollte die Schreibweise der
Pseudo-Opcodes vereinbart werden, denn auch hier sind sie eine Ausnahme.
Alle Pseudo-Opcodes beginnen mit dem Punkt ".". Darauf folgt der
eigentliche Name des Pseudo-Opcode. Da der Assembler Pseudo-Opcodes
entsprechend sehr leicht erkennt, braucht der Name des Pseudo-Opcodes nicht
vollständig angegeben werden. Es genügen soviele Zeichen, wie zur unver-
wechselbaren Unterscheidung notwendig sind (Also z.B. ".in" für ".include"
aber nicht nur ".i", da dies auch für ".if" stehen könnte). Zwischen Groß-
und Kleinschreibung wird nicht unterschieden.
.BYTE
Der ".byte"-Pseudo-Opcode dient zum Einfügen von Bytefolgen in den
Quelltext (z.B. Tabellen). Die Bytes werden als Operanden angegeben.
Entsprechend der Maximalzahl können also max. 32 Bytes pro Pseudo-Opcode
angegeben werden.
.WORD
Der ".word"-Pseudo-Opcode fügt 16-Bit-Worte im 6510-typischen Format
Low-Byte/High-Byte in den Quelltext ein. Anstatt ".word 1200" könnte man
also auch ".byte <1200,>1200" schreiben.
.BLOCK
Der ".block"-Pseudo-Opcode kann ein angegebenes Byte entsprechend der
angegebenen Anzahl oft in den Quelltext einfügen. Parameter 1 enthält die
Anzahl (max. 65535), Parameter 2 das Byte selbst. Dieser Befehl sollte
nicht zu großzügig angewendet werden, da er den Objektcode meist nur
unnötig verlängert.
.ASCII
Der ".ascii"-Pseudo-Opcode dient dazu, einen Text in den Objektcode
einzufügen. Der Text wird als Operand angegeben (Anführungszeichen nicht
vergessen) und von CrossAss mit Hilfe der Konvertierungstabelle angepasst.
.BASE
Der ".base"-Pseudo-Opcode definiert die Startadresse des Objektcodes und
dessen Dateinamen. Die Adresse wird als erster, der Dateiname inkl. Pfad
als zweiter Parameter angegeben. Durch mehrmaliges Verwenden des
".base"-Pseudo-Opcodes bietet CrossAss V1.0 als Besonderheit die
Möglichkeit des Objektcodesplitting. Das heißt, der Objektcode kann in
mehrere Blöcke (Objektcodedateien) an verschiedenen Adressen aufgesplittet
werden, wobei trotzdem blockübergreifend gearbeitet werden kann. Die
einzelnen Objektcodedateien müssen einzeln zum C64 übertragen werden.
Jeder Quelltext muß mindestens einen ".base"-Pseudo-Opcode enthalten, der
vor der ersten den Objektcode beeinflussenden Anweisung stehen muß.
.EQUAL
Mit dem ".equal"-Pseudo-Opcodes können Labels explizit definiert werden,
das heißt, der dem Label zuzuweisende Wert kann vom Programmierer selbst
angegeben werden. Der Labelname muß aber trotzdem als erstes in der Zeile
stehen, gefolgt vom Pseudo-Opcode. Dessen Operand schließlich ist der
zuzuweisende Wert. Wird ein Label in Abhängigkeit eines anderen Labels
definiert, so muß letzteres bereits vorher definiert worden sein, da die
Definition des abhängigen Labels ebenfalls in Pass 1 vorgenommen wird. Ein
Label kann grundsätzlich nur einmal definiert und nicht mehr geändert
werden (Ausnahme sind lokale Labels in Makroquelltexten) ! Übrigens: Die
Zeile "marke lda $2000" kann entsprechend durch die beiden
aufeinanderfolgenden Zeilen "marke .equal *" und "lda $2000" ersetzt
werden.
.MACRO - .ENDMACRO
Die beiden Pseudo-Opcodes ".macro" und ".endmacro" dienen zur Definition
eines Makros. Sie umschließen den Makroquelltext. Nach dem Pseudo-Opcode
".macro" wird als erster Parameter der Name des Makros OHNE Anführungszei-
chen angegeben (max. 32 Zeichen). Als zweiter Parameter wird optional die
Anzahl der Übergabeparameter hinzugefügt, welche Werte von 1-10 (ein-
schließlich) annehmen kann. Wird 0 oder gar kein zweiter Parameter angege-
ben, so werden keine Übergabeparameter verwendet. Innerhalb des Makros kann
wie oben beschrieben auf die Übergabeparameter zugegriffen werden. Alle
innerhalb des Makroquelltextes definierten Labels gelten als lokale Labels
und sind nur dort erreichbar. Anders als in Hochsprachen sind
Überlappungen von globalen Labels durch lokale Labels gleichen Namens nicht
erlaubt.Innerhalb eines Makroquelltextes darf aus programmtechnischen Grün-
den weder ein weiteres Makro definiert noch eine Datei per ".include" ein-
gebunden werden, was aber logisch ist, da im ersten Fall Makros bei mehrma-
ligem Aufruf mehrmals definiert werden würden und letzterer Fall nur zu un-
nötig langen Objektcodedateien beitragen würde. Makroaufrufe können jedoch
sehr wohl geschachtelt werden (max. 32 mal), wobei jedoch jedes Makro be-
reits vor seinem Aufruf bekannt sein muß (sowohl in Pass 1 als auch in Pass
2).
.IF - .ELSE - .ENDIF
Wie aus Hochsprachen bekannt, dienen if-else-endif-Konstruktionen zur
bedingten Bearbeitung, in unserem Fall zur bedingten Assemblierung. Ist
die angegebene Bedingung erfüllt wird der Teil zwischen ".if" und ".else"
assembliert, der Teil nach ".else" überlesen. Ist die Bedingung nicht
erfüllt, wird der Teil zwischen ".if" und ".else" überlesen und zwischen
".else" und ".endif" assembliert. Der ".else"-Teil kann dabei entfallen,
so daß nur eine ".if"-".endif"-Konstruktion entsteht, bei der bei nicht
erfüllter Bedingung nichts assembliert wird. ".if"-".else"-".endif"-Kon-
struktionen können beliebig ineinander oft (max. 65535 mal) verschachtelt
werden
Die Bedingung selbst wird dem ".if"-Pseudo-Opcode als Operand übergeben.
Dabei wird in zwei Verwendungsweisen unterschieden:
- Logische Verknüpfung zweier Operanden
- Prüfung auf Berechenbarkeit eines Operanden
In ersterem Fall werden die Ergebnisse zweier Terme logisch miteinander
verknüpft und entsprechend dem Ergebnis assembliert. Als erster Operand
des ".if"-Pseudo-Opcodes muß zunächst der Vergleichsoperator angegeben
werden, mit dem die beiden Vergleichsoperanden verknüpft werden sollen.
CrossAss kennt vier Möglichkeiten, wobei KEINE Kombinationen möglich sind:
= prüft auf Gleichheit der beiden Operanden
! prüft auf Ungleichheit der beiden Operanden
< prüft, ob erster Operand kleiner als zweiter Operand
> prüft, ob erster Operand größer als zweiter Operand
Als zweiter und dritter Operand des Pseudo-Opcodes werden dann die
Vergleichsoperanden angegeben. Diese etwas ungewöhnliche Schreibweise soll
an zwei Beispielen verdeutlicht werden:
.if =,Label1,Label2 wahr, wenn "Label1" gleich "Label2"
.if <,$c000+23*3,*+10 wahr, wenn $c000+23*3 kleiner 10 +
Programmcounter
Bei der zweiten Verwendungsmöglichkeit des ".if"-Pseudo-Opcodes wird ge-
prüft, ob ein Term berechnet werden kann, oder ob dabei ein Fehler auftritt
(natürlich mit Unterdrückung einer Fehlermeldung die zum Abbruch der
Assemblierung führen würde). Dies ist hauptsächlich dann nützlich, wenn
eine Includedatei nur dann eingebunden werden soll, wenn ein Label, das
diese Includedatei kennzeichnet, noch nicht definiert ist. Der Sinn
solcher Maßnahmen wird später noch ausführlich erklärt. Die Zahl der
Vergleichsoperatoren beschränkt sich in diesem Fall auf zwei, nämlich:
= wahr, wenn bei der Berechnung kein Fehler auftritt
! wahr, wenn bei der Berechnung ein Fehler auftritt
Natürlich kann es auch hier einen ".else"-".endif"-Zweig geben. Auch
hierzu noch zwei Beispiele
.if !,Marke wahr, wenn "Marke" nicht definiert
.if =,1/0 falsch, da 1/0 nicht berechnet werden kann
.INCLUDE
Der ".include"-Pseudo-Opcode dient vordergründig dazu, eine Datei in den
laufenden Quelltext ab der Position des Pseudo-Opcodes einzubinden um nach
Beendigung der Assemblierung dieser Datei mit der Zeile nach dem
Pseudo-Opcode fortzufahren. Dabei kann innerhalb einer solchen
Includedatei eine weitere Datei eingebunden werden, da maximal 32
Verschachtelungen möglich sind. Der Verwendungszweck des Pseudo-Opcodes
liegt aber weniger in der Auslagerung von Quelltextteilen auf Disk oder
Festplatte aufgrund von Speichermangel, da dieser auf dem Amiga seltener
auftritt und außerdem von CrossAss sowieso nur immer die aktuell zu
assemblierende Zeile im Speicher gehalten wird. Es ist aber doch wohl so,
daß bestimmte Labels, Makros oder gar Quelltextteile immer wieder verwendet
werden (Hardwareregister, Betriebssystemaufrufe etc.). Was liegt also
näher, als deren Definitionen, anstatt sie jedesmal neu an den Quelltext
anzufügen, einfach in eine Datei auszulagern, die man dann nur noch bei
Bedarf hinzu "includen" muß. So kann man sich eigene Bibliotheken
erstellen, die bei Gebrauch immer zur Verfügung stehen. Später wird noch
einmal genauer auf solche Bibliotheken eingegangen, da mit ihnen äußerst
effizient gearbeitet werden kann, wenn man sich an einige wenige Regeln
hält. Außerdem sind bereits einige vorgefertige Bibliotheken Bestandteil
des 6510-Developers-Packet. Der ".include"-Pseudo-Opcode erhält daher als
einzigen Parameter den Dateinamen plus Pfad der einzubindenden Datei. Sol-
lte sich der ".include"-Pseudo-Opcode in einem nichtassemblierten Bereich
befinden ("falscher" Zweig einer ".if"-".else"-".endif"-Konstruktion),
so wird auch nichts eingebunden.
.APPEND
Der ".append"-Pseudo-Opcode steht wegen der geringen Verwendungs-
wahrscheinlichkeit am Schluß. Er dient zum Anhängen einer weiteren
Quelltextdatei an das Ende der aktuell bearbeiteten. Der einzige Fall (den
ich mir vorstellen kann), bei dem dies nötig wird, ist, daß bei einem
Diskettensystem ein Quelltext nicht mehr ganz auf Disk Platz findet (also
größer als 880 KByte ist!) und deshalb auf einer anderen Disk und
entsprechend in einer anderen Datei fortgeführt werden muß. Im Gegensatz
zu ".include" wird dabei immer (auch wenn ".append" in einem nicht zu
assemblierenden Bereich steht) mit der als Parameter des ".append"-
Pseudo-Opcodes angegebenen Datei fortgefahren und nicht mehr zurückgekehrt,
da CrossAss erwartet, daß nach ".append" der alte Quelltext zu Ende ist.
Zum Schluß der Erklärung des Quelltextaufbaus sollen nun noch einige
Worte zum Thema "Includebibliotheken" fallen. Bei richtigem Einsatz können
diese Bibliotheken zu einem mächtigen Werkzeug werden, das man als
Programmierer bald nicht mehr missen möchte. Zunächst sollte jedoch ein
einheitlicher Aufbau der Includebibliotheken vereinbart werden, sofern man
keine bösen Überraschungen erleben will. Außerdem können, wenn diese
wenigen Regeln eingehalten werden, Includebibliotheken leicht weitergegeben
werden. Zu Beginn einer Bibliothek sollte ein Kommentarskopf stehen, der
kurz den Inhalt der Bibliothek umreißt. Die Bibliothek sollte natürlich
auch nur das enthalten, was der Kopf (und ihr Dateiname!) verspricht. Ein
zu Beginn der Bibliothek definiertes Dummy-Label soll als Prüflabel dienen.
Bei größeren Bibliotheken, die andere Bibliotheken, von denen sie abhängig
sind, einbinden, kann es leicht geschehen, daß durch Mehrfacheinbindungen,
Labels oder Makros doppelt zu definieren versucht werden. Wird vor der
Einbindung geprüft, ob das der Bibliothek gehörende Dummy-Label bereits
existiert, so kann dies verhindert werden. Das Label sollte daher einen
markanten, aussagekräftigen Namen besitzen. Sein Wert ist egal, da nur die
Tatsache des "definiert Seins" entscheidet. Bei Bibliotheken, die Makros
enthalten, sollte besonders gut kommentiert werden, was welches Makro
bewirkt. Insbesondere gilt dies auch für die Übergabeparameter (wenn
vorhanden).
Vor einer Fehlerquelle soll jedoch gewarnt werden: Das Prinzip des
2-Pass-Assemblers verbietet, daß eine bedingt eingebundene Datei auch in
Pass 2 eingebunden und damit assembliert wird. Bei reinen Label- oder
Makrobibliotheken ist dies nicht weiter schlimm, wohl aber, wenn die
Bibliothek echten Quelltext enthält. Dieser wird bei Pass 2 einfach
vergessen ! Quelltext (direkt zu assemblierenden Quelltext, nicht
Makroquelltext) enthaltende Bibliotheken dürfen deshalb NIE bedingt einge-
bunden werden. Sie sollten von anderen Bibliotheken getrennt (am besten in
verschiedenen Verzeichnissen) aufbewahrt werden.
Das 6510-Developers-Packet umfaßt bereits fünf fertige Includebiblio-
theken:
Basic-ROM.inc
Kernel-ROM.inc
SID.inc
CIA.inc
VIC.inc
Basic-Start.inc
"Basic-ROM.inc" und "Kernel-ROM.inc" enthalten die Einsprungsadressen der
Betriebssystemroutinen des C64 mit deren Abkürzungen. VIC.inc und SID.inc
enthalten die Adressen der Register des VIC bzw. SID, während CIA.inc nur
die Offsets der CIA-Register und die Basisadressen der beiden CIAs enthält,
welche entsprechend addiert werden müssen. Alle Bibliotheken halten sich
an die obigen Regeln, die als Prüflabel gedachten Dummies sind die jeweils
als erstes definierten Labels. Die Includedatei "Basic-Start.inc" enthält
gegenüber den anderen Dateien quelltextmodifizierende Anweisungen und darf
deshalb, wie oben erklärt, NIE bedingt eingebunden werden! Die Datei
bietet komfortable Möglichkeiten, einen Basic-Kopf an ein Assemblerprogramm
zu binden (so ein Programm kann dann ganz normal mit LOAD "....",8 geladen
und mit RUN gestartet werden). Da die Includedatei komplizierter zu
handhaben ist, befindet sich in ihrem Kommentarskopf eine ausführliche
Verwendungsbeschreibung. Wie die Datei gehandhabt wird, kann außerdem am
Beispiel des Source-Codes von "Transfer" ersehen werden.
Die Namensendung ".inc" ist bei Includedateien übrigens nicht zwingend.
Wie Dateien heißen, ist CrossAss im allgemeinen egal. Trotzdem sollte hier
eine gewisse Ordnung eingehalten werden. Ein reibungsloser
Assembliervorgang wird Ihnen dies lohnen, wenn solche Regeln allgemein
eingehalten werden. Lassen Sie deshalb alle Quelltextdateien auf ".src",
alle Objektcodedateien auf ".obj", alle Includedateien auf ".inc" und
schließlich alle Konvertierungsdateien (wird später erklärt) auf ".con"
enden und legen Sie sie separat in verschiedene Verzeichnisse.
Der Amiga bietet die Möglichkeit der Zuweisung logischer Laufwerke. Das
bedeutet, daß einem bestimmten Pfad ein Name zugewiesen wird, über den
dieser Pfad dann, wie ein neues Laufwerk, angesprochen werden. Unter
Amiga-DOS übernimmt dies der "Assign"-Befehl. Gerade diese Möglichkeit
kann bei der Arbeit mit CrossAss vieles erleichtern. Wird auf jedem System,
auf dem CrossAss verwendet wird, den einzelnen Verzeichnissen, die
Quelltexte, Objektcodes etc. enthalten, ein logisches Laufwerk mit jeweils
einheitlichem Namen zugewiesen, so kann jeder Benutzer ohne Probleme auf
diese Laufwerke zugreifen und wird immer im richtigen Pfad landen.
Folgende logische Laufwerke sollten daher auf jedem System die angegebenen
Pfade repräsentieren:
SOURCE: Pfad des Verzeichnisses, das Quelltexte enthält
OBJECT: Pfad des Verzeichnisses, in das Objektcodes gelangen
INCLD: Pfad des Verzeichnisses, in dem sich alle Include-
Dateien befinden
CONVERT: Pfad des Verzeichnisses, in dem sich alle Konver-
tierungstabellen befinden
Gerade die Arbeit mit Bibliotheken wird erst hierdurch richtig möglich, da
nun ganz global auf eine Bibliothek mit "INCLD:Bibliothekname.inc"
zugegriffen werden kann, ohne sich Sorgen zu machen, wo sich die Dateien
eigentlich tatsächlich befinden. Die für die Laufwerke notwendigen
"assign"-Kommandos sollten Sie sich entweder in Ihre User-Startup setzen,
oder in ein IconX-Script, das Sie vor dem Start von CrossAss aufrufen.
Nachdem nun alles zum Aufbau des Quelltextes gesagt ist, kommen wir zur
Bedienung des Programms selbst. CrossAss integriert sich in die
Benutzeroberfläche des Amiga, so daß die Bedienung des Programms für keinen
Amiga-Anwender zum Problem werden sollte. Obwohl CrossAss auch unter
Kickstart 1.3 arbeitet, sollte die Verwendung unter Amiga-OS2.0 vorgezogen
werden, da CrossAss dann den Filerequester der "asl.library" benutzen kann.
CrossAss besitzt selbst keinen Filerequester. Unter Kickstart 1.3 erfolgt
die Dateinameneingabe über Tastatur.
Nach dem Start von CrossAss erscheinen zunächst zwei sich überlagernde
Windows, wobei das obere Window hauptsächlich nur eine Copyright-Erklärung
enthält und deshalb durch Klicken seines Close-Gadgets sofort geschlossen
werden kann.
Das Copyright-Window gibt aber auch einige Informationen über von
CrossAss belegte Speicherbereiche, auf die jetzt genauer eingegangen werden
soll. CrossAss belegt für seine Arbeit drei Speicherbereiche, deren Größe
von Ihnen bestimmt werden kann. Die Speicherbereiche tragen die Namen
Labeltabelle, Makrotabelle und Makrospeicher. Die Labeltabelle bzw.
Makrotabelle enthalten, wie ihre Namen ja aussagen, alle wichtigen Daten
der Labels bzw. Makros. Ihre Größe entscheidet darüber, wieviele Labels
bzw. Makros überhaupt verwendet werden können. Der Unterschied zwischen
Makrotabelle und Makrospeicher ist der, daß in der Makrotabelle alle Daten
über die Makros, im Makrospeicher jedoch die Makroquelltexte selbst
gespeichert werden. Makrotabelle und Makrospeicher müssen also immer in
einem vernünftigen Verhältnis zueinander stehen, denn was nützt eine große
Makrotabelle, wenn die Quelltexte der Makros nicht im Makrospeicher Platz
finden?
Nach Schließen des Copyright-Windows wird das gesamte Statuswindow von
CrossAss sichtbar. In diesem Fenster werden laufende Ausgaben während der
Assemblierung gemacht und alle Fehlermeldungen angezeigt. Hier können Sie
Länge, Anfangs- und Endadresse des Objektcodes ablesen, die Dateinamen der
aktuellen Quelltext- bzw. Objektcodedateien, die Anzahl der definierten
Labels und Makros, die aktuell assemblierte Zeile im Quelltext (neben
"Zeile:"), die Anzahl der bisher insgesamt assemblierten Zeilen (neben
"Zeilen insg."), sowie last but not least ob ein Fehler aufgetreten ist
bzw. was CrossAss gerade tut.
Das Window besitzt zwei Gadgets, darunter ein Close-Gadget, mit dem das
Programm beendet werden kann. Das zweite Gadget trägt die Aufschrift
"Start" und dient zum Starten der Assemblierung. Wird es betätigt,
erscheint je nach Ihrer Amiga-OS-Version der asl-Filerequester oder ein
Stringgadget zur Dateiauswahl. Wird der Auswahlvorgang durch das am
jeweiligen Eingabefenster befindlichen Close-Gadget abgebrochen, erfolgt
natürlich keine Assemblierung. Ansonsten ändert sich die Aufschrift des
"Start"-Gadgets in "Stop" und die Assemblierung beginnt. Während der
Assemblierung wird zyklisch der Fensterinhalt des Statuswindow erneuert,
laut (änderbarer) Voreinstellung nach jeweils 100 assemblierten Zeilen.
Wird die Assemblierung nicht durch das "Stop"-Gadget abgebrochen, endet sie
entweder, wenn CrossAss einen Fehler entdeckt oder das Ende des Quelltextes
erreicht und die Assemblierung somit erfolgreich war.
Während der Assemblierung kann die Anzeige "Quelldatei" in "akt. Makro"
wechseln, nämlich dann, wenn CrossAss einen Makroquelltext assembliert. Da
CrossAss sich nicht die Datei und Position des Makroquelltextes merkt,
sondern diesen im Makrospeicher hält, erfolgt die Anzeige auf diese Weise.
Die Anzeige "Zeile" beginnt dabei bei 0, so daß bei einem Fehler die
angegebene Zeile, die fehlerhafte Zeile im Makroquelltext darstellt.
CrossAss besitzt eine eigene Menüleiste mit einer ganzen Reihe weiterer
Funktionen, die nun im einzelnen erklärt werden sollen.
Menü "Datei", Menüpunkt "Übertragen"
Wird der Menüpunkt aufgerufen, erscheint wieder der der OS-Version
entsprechende Filerequester zur Auswahl einer Objektcodedatei. Wurde zuvor
bereits assembliert, erscheint der Namen der zuletzt erzeugten Datei
automatisch, so daß, wenn kein anderer gewählt werden soll, direkt
fortgefahren werden kann. Nach der Auswahl beginnt die Übertragung. Amiga
und C64 müssen dabei mit dem Parallelkabel verbunden sein und eine der
beiden Empfangsprogramme auf dem C64 gestartet worden sein. Die
Übertragung läßt sich nicht abbrechen, da die Kontrolle während der ganzen
Übertragung an das Amiga-Betriebssystem übergeben wird. Sollte die
Verbindung nicht stimmen, hängt der Computer und gibt CrossAss die
Kontrolle nicht mehr zurück. Prüfen Sie deshalb vorher die Verbindung.
Trotzdem: Verbinden Sie die Computer NIEMALS in eingeschaltetem Zustand!!
Menü "Datei", Menüpunkt "Information"
Sollten Sie einmal das starke Bedürfnis haben, den Namen des Authors
oder die Copyrightmeldung zu lesen, dann sollten Sie diesen Menüpunkt
aufrufen. Es erscheint das Copyright-Window, wie nach dem Start von
CrossAss.
Menü "Datei", Menüpunkt "Ende"
Dieser Menüpunkt beendet CrossAss.
Menü "Tabellen", Menüpunkt "Labels"
Über das "Tabellen"-Menü macht CrossAss dem Benutzer seine internen
Tabellen zugänglich. Über den "Labels"-Menüpunkt, kann CrossAss' Label-
tabelle sichtbar gemacht werden. Sie erscheint (wie alle Tabellen des
"Tabellen"-Menüs") in einem eigenen Window. Die Labels werden in einem
Kasten dargestellt, der max. 15 Einträge enthalten kann. Durch Betätigen
der Pfeilgadgets oder durch Benutzen des Rollbalkens kann der Inhalt des
Kastens gerollt werden. Die Labels erscheinen mit ihren Werten in
dezimaler und hexadezimaler Form, wie im Tabellenkopf über dem Kasten
angegeben. Durch das Close-Gadget kann das Tabellen-Window geschlossen
werden. Sollten bei der Anzeige plötzlich mehrere Labels gleichen Namens
mit verschiedenen Werten angezeigt werden, so handelt es sich hierbei um
lokale Labels, die in Makros definiert wurden.
Menü "Tabellen", Menüpunkt "Makros"
Entsprechend dem "Labels"-Menüpunkt erscheint hier der Inhalt der
Makrotabelle. Die Makros werden mit Namen, Länge im Makrospeicher und
ihrer Übergabeparameteranzahl angegeben.
Menü "Tabellen", Menüpunkt "Blöcke"
Die Möglichkeit des Objektcodesplittings durch CrossAss in verschiedene
Objektcodedateien bietet zahlreiche Vorteile. Allerdings wird im Status-
window nur der aktuelle Objektcodedateinamen angezeigt. Über den Menüpunkt
"Blöcke" können alle Objektcodedateinamen inkl. Start-, Endadresse und
Länge sichtbar gemacht werden. Allerdings merkt sich CrossAss nur 32
Objektcodedateinamen, was wohl völlig ausreicht. Der ".base"-Pseudo-Opcode
kann aber dennoch mehr als 32 mal im Quelltext verwendet werden.
Menü "Tabellen", Menüpunkt "Mnemonics"
Für seine internen Arbeiten benötigt CrossAss eine Tabelle, die zusätz-
lich zu den Namen der einzelnen Mnemonics auch ihre Adressierungsarten
angibt. Über den "Mnemonics"-Menüpunkt wird dem Programmierer diese
Tabelle, sozusagen als besonderer Service, zugänglich gemacht. Besonders
bei sehr optimierter Programmierung, kann man leicht in die Versuchung
geraten, z.B. ein ASL-Mnemonic mit Zeropage-Y-indizierter Adressierung zu
verwenden, weil dies eben so gut passen würde, obwohl es der 6510 nicht
ermöglicht. Die Tabellenkopf enthält Abkürzungen für die einzelnen Adres-
sierungsarten. Je nachdem, ob ein Mnemonic eine Adressierungsart kennt,
steht in dieser Spalte ein Stern ("*"). Die einzelnen Abkürzungen sind:
IM : immediate
AB : absolut
AX : absolut x-indiziert
AY : absolut y-indiziert
ZP : Zeropage
ZX : Zeropage x-indiziert
ZY : Zeropage y-indiziert
ID : indiziert indirekt
DI : indirekt indiziert
RE : relativ
IN : indirekt (nur JMP-Mnemonic)
AI : Akkumulator/implement (wird vom Assembler nicht unterschieden)
Menü "Einstellungen", Menüpunkt "Ändern"
Das "Einstellungen"-Menü enthält alle Funktionen, die mit der Vorein-
stellungsdatei "s:CA.prefs" zu tun haben. Diese Datei wird beim Start von
CrossAss geladen und enthält alle vom Benutzer gewünschten Eingaben. Ist
diese Datei noch nicht vorhanden, wie z.B. beim allerersten Start von
CrossAss, so wird sie, mit den Grundeinstellungen gefüllt, erzeugt.
Nach Aufruf des Menüpunkts "Ändern" erscheint das Einstellungswindow von
CrossAss mit insgesamt vier String- und zwei Boolean-Gadgets, mit denen die
Einstellungen manipuliert werden können. Eines der beiden Boolean-Gadgets
trägt die Aufschrift "OK". Bei Betätigung schließt das Einstellungsfenster
und die neuen Einstellungen werden aktiv. Wird das Fenster durch das
ebenfalls vorhandene Close-Gadget geschlossen, werden die aktuellen
Veränderungen vergessen und die vor Aufruf des "Ändern"-Menüpunkts aktiven
Einstellungen zurückgeholt.
Die ersten drei String-Gadgets dienen zur Größenbestimmung von Label-,
Makrotabelle und Makrospeicher. Für die Größe der Label- und Makrotabelle
muß die Anzahl der Labels bzw. Makros angegeben werden, die in die
Tabellen passen sollen. Rechts daneben wird dann angezeigt, wieviel
Speicher in Byte diese Anzahl benötigt. Erscheint als Anzeige 0, so
übersteigt die Größe der Tabelle den freien Speicher. Die Größe des
Makrospeichers muß direkt in Bytes angegeben. Wie bereits erwähnt, sollte
man ein vernünftiges Verhältnis zwischen Makrospeicher und Makrotabelle
einhalten, so daß der Quelltext der in der Makrotabelle speicherbaren
Makros auch wirklich im Makrospeicher Platz findet. Tatsächlich belegt
werden die drei von CrossAss benötigten Speicherbereiche übrigens erst bei
Beginn der Assemblierung.
Das vierte String-Gadget mit der Überschrift "Refresh-Rate" gibt an, wie
oft CrossAss während der laufenden Assemblierung den Inhalt des Status-
windows erneuern soll. Nach dem eingetragenen Wert von Zeilen wird der
Windowtext "refreshed". Sehr kleine Werte ermöglichen ein gutes Verfolgen
des Assembliervorganges, bremsen diesen jedoch stark ab, während große
Werte Zeit sparen helfen.
Das zweite Boolean-Gadget trägt die Aufschrift "Sort". Es bestimmt, ob
die Labels nach Beenden oder Abbruch der Assemblierung alphabetisch
sortiert werden sollen. Das Gadget ist ein Toggle-Gadget und kann somit
als Schalter benutzt werden, um die Sortierung an- oder auszuschalten. Als
Sortieralgorithmus wird "Straight Insertion" benutzt (nicht der schnellste,
aber doch mehr als doppelt so schnell wie Bubble-Sort). Durch Abschalten
der Sortierung kann bei langen Labeltabellen Zeit gespart werden. Die
Labels werden dann in der Reihenfolge der Definition angezeigt.
Menü "Einstellungen", Menüpunkt "Speichern"
Erweisen sich modifizierte Einstellungen als besonders gut, so können
Sie sie mit dem Menüpunkt "Speichern" zusammen mit einer evtl. vorher
geladenen Konvertierungstabelle (siehe unten) in die Datei "s:CA.prefs"
speichern. Die Einstellungen inkl. Konvertierungstabelle stehen dann nach
jedem Start von CrossAss sofort zur Verfügung.
Menü "Einstellungen", Menüpunkt "Laden"
Erweisen sich modifizierte Einstellungen hingegen als unbrauchbar,
nachdem Sie bereits das Einstellungswindow verlassen haben, so können Sie
mit dem Menüpunkt "Laden" die zuletzt gespeicherten Einstellungen wieder
laden. Testen Sie deshalb Ihre Einstellungen, bevor Sie sie speichern.
Menü "Einstellungen", Menüpunkt "KonvertTab laden"
Mehrmals wurde bereits von der Konvertierungstabelle gesprochen, die
CrossAss benutzt, um Texte und Zeichen, bevor sie in den Quelltext
eingefügt werden, anzupassen. Dies ist notwendig, da der Amiga und der C64
verschiedene ASCII-Tabellen verwenden, begründet durch ihre verschiedenen
Zeichensätze. Die Konvertierungstabelle kann beliebig geändert werden. Da
sie jedoch 256 Einträge besitzt, die man dem Benutzer wohl nicht zutrauen
kann, jedes mal eintippen zu müssen, wurde die Möglichkeit geschaffen, die
Konvertierungsdatei mit einer Beschreibungsdatei zu beschreiben. Eine
solche Beschreibungsdatei wird mit Ihrem Texteditor erstellt. Jede Zeile
enthält dann zunächst einen Amiga-ASCII-Code und durch mindestens ein
Leerzeichen getrennt den entsprechenden C64-Code. Zum Erstellen der
eigentlichen Konvertierungstabelle benutzt CrossAss ein Verfahren, das am
besten am einem Beispiel verdeutlicht werden kann. Angenommen die
Beschreibungsdatei sieht wie folgt aus:
0 10
2 40
5 0
CrossAss liest zunächst die erste Zeile und nummeriert ab dem angegebenen
Amiga-Code die Konvertierungstabelle beginnend mit dem C64-Code fortlaufend
durch. Diese würde nach der ersten Zeile wie folgt aussehen:
Amiga-Code C64-Code
0 10
1 11
2 12
3 13
4 14
5 15
6 16
7 17
usw.
Danach wird die zweite Zeile interpretiert und wieder ab dem Amiga-Code
durchnummeriert:
Amiga-Code C64-Code
0 10
1 11 (bis hier zugewiesen durch Zeile 1)
2 40 (ab hier zugewiesen durch Zeile 2)
3 41
4 42
5 43
6 44
7 45
usw.
Mit der dritten Zeile wird genauso verfahren:
Amiga-Code C64-Code
0 10
1 11 (bis hier zugewiesen durch Zeile 1)
2 40
3 41
4 42 (bis hier zugewiesen durch Zeile 2)
5 0 (ab hier zugewiesen durch Zeile 3)
6 1
7 2
Mit diesem Verfahren kann auf einfache Weise mit wenigen Angaben eine
Konvertierungstabelle erstellt werden. Die Amiga-Codes müssen jedoch immer
klein beginnen und dann ansteigen, da sonst vorhergehende Zuweisungen
wieder ganz überschrieben werden. Die Zahlen können in allen Zahlen-
systemen (8 Bit) angegeben werden, allerdings nicht als Terme. Die Angabe
direkt als Zeichen scheidet aus, da diese durch eine noch nicht
vollständige Konvertierungstabelle (eben die gerade im Aufbau befindliche)
konvertiert würden, was falsche Werte ergäbe. Konvertierungstabellen
dürfen und sollten auch Kommentare enthalten. Eine Kommentarszeile muß mit
einem Semikolon (";") in der ersten (1.) Spalte beginnen. Auch Leerzeilen
benötigen ein Semikolen!
Das 6510-Developers-Packet enthält bereits zwei Konvertierungstabellen,
die wie vereinbart immer über das logische Laufwerk "CONVERT:" erreichbar
sein sollten. "C64.con" wandelt Amiga-ASCII-Codes in C64-ASCII-Codes,
während "SCode.con" in C64-Bildschirm-Codes wandelt.
Nach Aufruf des Menüpunktes erscheint der dem verwendeten OS ent-
sprechende Filerequester zur Auswahl der Beschreibungsdatei. Danach
startet die Generierung der Tabelle. Kann CrossAss die Beschreibungsdatei
nicht richtig interpretieren, erscheint eine Fehlermeldung.
Menü "Drucken", Menüpunkt "Quelldatei"
Das letzte der vier Pull-Down-Menüs von CrossAss enthält Funktionen, die
zum Ausdruck von Quelltext, Label-, Makro- und Blocktabelle dienen. Der
Ausdruck erfolgt dabei im Normalfall nicht direkt auf den Drucker, sondern
in eine Textdatei. Dies ist logisch, da ja das Parallelkabel vom C64 zum
Amiga den Parallelport belegt, an dem normalerweise ein Drucker
angeschlossen ist. Sollte dies nicht der Fall sein (oder sollte Ihr
Drucker am seriellen Port angeschlossen sein), kann im jeweiligen
Filerequester natürlich auch "prt:" als Dateinamen eingegeben werden. Wird
bei den Druckfunktionen eine bereits vorhandene Datei ausgewählt, so werden
die auszudruckenden Daten an diese angehängt. Die entstandene Textdatei
kann mit einem Texteditor bearbeitet werden.
Der Menüpunkt "Quelldatei" dient zum Online-Drucken des Quelltextes mit
den erzeugten Opcodes während der Assemblierung. Dies ist nur so möglich,
da CrossAss ja jeweils nur die aktuell assemblierte Zeile im Speicher hält
und sich den Quelltext nicht merkt. Nach Aufruf des Menüpunktes und der
Dateinameneingabe erscheint deshalb nur die Meldung, daß der Quelltextdruck
nun eingeschaltet ist. Der Druck erfolgt dann bei jedem Assembliervorgang,
solange bis die Funktion durch nochmaliges Auswählen des Menüpunktes wieder
abgeschaltet wird. Bei Makrodefinitionen wird nur deren Kopf- und Fußzeile
ausgedruckt. Der Quelltext mit angepassten Opcodes wird bei jedem Aufruf
des Makros ausgedruckt.
Menü "Drucken", Menüpunkt "Labels"
Der Menüpunkt "Labels" dient zum Drucken der Labeltabelle in eine
Textdatei. Da die Labeltabelle erst nach vollendeter Assemblierung
fertiggestellt ist, kann sie erst nach deren Beendigung gedruckt werden.
Menü "Drucken", Menüpunkt "Makros"
Die Funktionsweise des "Makros"-Menüpunktes entspricht der des "Labels"-
Menüpunktes, mit dem Unterschied, daß die Makrotabelle gedruckt wird.
Menü "Drucken", Menüpunkt "Blöcke"
Die letzte der Druckfunktionen druckt schließlich die vom Objektcode-
splitting per ".base" und dem gleichnamigen Menüpunkt des "Tabellen"-Menüs
bekannte Blocktabelle aus. Die Bedienung ist dieselbe wie bei den obigen
Menüpunkten "Makros" bzw. "Labels".
Nachdem alle Funktionen von CrossAss hinreichend ausführlich erklärt
worden sind, dürfte einer reibungslosen Arbeit nichts mehr entgegen stehen.
Im Anschluß sollten noch einige Hinweise zu den beiden Empfangsprogrammen
für den C64 gemacht werden.
Die erste Empfangsroutine "Transfer" dient zum direkten Speichern der
übertragenen Daten auf Diskette. Sie eignet sich deshalb besonders gut für
große Programmprojekte (für die das 6510-Developers-Packet ja geschaffen
wurde). Nach dem Start des Programmes mit
LOAD "TRANSFER",8
und <RUN> erscheint eine kleine Titelmeldung und eine Aufforderung zur
Eingabe des Dateinamens unter dem die Daten gespeichert werden sollen. Ist
eine Datei mit diesem Namen bereits vorhanden wird sie zuvor (und ohne
Warnung !) per SCRATCH-Befehl gelöscht, bevor die Daten gespeichert werden.
Transfer startet dann die Übertragungsroutine. Daß Transfer von Disk
geladen werden muß, sollte auch bei Floppies ohne Speeder nicht stören, da
Transfer nur 2 Blöcke auf Disk belegt. Obwohl bei der parallelen
Übertragung jeweils 8 Bit übertragen werden erscheint diese bei Transfer
relativ langsam. Das liegt jedoch nicht an der Übertragungsroutine,
sondern an den langsamen Diskettenroutinen des C64-Betriebssystem. Ein
Floppyspeeder schafft hier Abhilfe. Die Übertragung braucht nicht auf
beiden Rechnern gleichzeitig gestartet zu werden (was auch nur schwer
möglich wäre); die Rechner warten selbstständig aufeinander.
Die zweite Empfangsroutine "TransRAM" überträgt die empfangenen Daten
nur ins RAM des C64. Sie eignet sich zum schnellen Austesten kleinerer
Routinen. Eine Dateinameneingabe ist überflüssig. Die Routine wird mit
LOAD "TRANSRAM",8,1
geladen. SYS 53048 startet die Empfangsroutine, die das obere Ende des 4
KByte-Bereich ab 49152 belegt. TransRAM meldet "waiting for data" und
sobald die ersten Daten vom Amiga ankommen "receiving from xxxxx". xxxxx
ist dabei die von CrossAss mit übertragene Startadresse . Die Übertragung
geht dabei durch Fehlen der Diskettenzugriffe wesentlich schneller. Ist
die Übertragung beendet, erscheint zusätzlich die Endadresse. Tritt ein
Fehler auf, meldet TransRAM "failed". Für solch einen Fehler kann es zwei
Gründe geben:
1. Die Startadresse wurde unvollständig übertragen (die Übertragung
brach also folglich bereits nach einem Byte ab)
2. Das Highbyte der Adresse, an die die Daten übertragen werden sollen,
überstieg den Wert 255 (Speicherende).
Beide Empfangsroutinen sind übrigens bereits mit CrossAss entwickelte
Programme, die mit einer alten, großteils in Basic geschriebenen Empfangs-
routine übertragen wurden. Die Sourcecodes "Transfer.src" bzw.
"TransRAM.src" können wie vereinbart über das logische Laufwerk SOURCE:
erreicht werden.
Zum Schluß noch zur Abrundung der Anleitung noch einige Tips, die sich
als hilfreich erwiesen haben:
Die Pseudo-Opcode-Konstruktion ".if"-".else"-".endif" erlaubt, wie
bereits gesagt keine Kombination von Vergleichsoperatoren. Die beiden
häufig benötigten Vergleichsoperatoren größer/gleich ">=" und kleiner/
gleich "<=" lassen sich jedoch einfach erzeugen, indem der Block zwischen
".if" und ".else" leer gelassen wird. Beispiele:
.if <,lab,10 ;"Gegenteil" von >=
.else
lda $2000 ;nur wenn dieses NICHT erfüllt ist,
.endif ;wird assembliert.
bzw.
.if >,lab,10
.else
lda $2000
.endif
Die Adressierungsart der Zeile
jmp (2312+43)-(3+2)
würden Sie sicherlich richtig mit "JMP-absolut" beantworten, auch wenn der
Term der Adresse geklammert ist. CrossAss ist da anderer Meinung. Die
Routinen zur Identifizierung der Adressierungsart beachten aus
Geschwindigkeitsgründen nur die äußersten Klammern und erkennen diese als
Kennzeichen der Adressierungsart "JMP-indirekt". Da diese Klammern dann
zusätzlich noch entfernt werden, gerät alles durcheinander. Um diesem
Fehler zu entgehen, gibt es drei Möglichkeiten:
1. Sie vermeiden grundsätzlich Klammern am Anfang und Ende eines
JMP-Operanden, so daß CrossAss garnicht auf die Idee kommt, eine
indirekte Adressierung zu interpretieren.
2. Sie fügen am Anfang oder am Ende eine Dummy-Rechenoperation hinzu,
die nur dazu dient, die Verwechslung auszuschließen:
JMP 0+(2312+43)-(3+2)
JMP (2312+43)-(3+2)*1
3. Sie verwenden anstatt der runden Klammern eckige Klammern, die nicht an
Adressierungsmerkmal verwendet werden dürfen. Eine Zeile
JMP [2312+43]-[3+2]
wird demnach korrekt assembliert.
Ähnliche Probleme gibt es bei der indizierten Adressierung. Hier können
verschiedene Fehler auftreten, wie z.B. das CrossAss meldet, das
"fehlerhafte" Mnemonic kenne keine indiziert indirekte Adressierung. Die
obigen Tricks helfen aber immer. Sollte obige Anweisung wirklich ein
indirektes JMP-Mnemonic sein, so müssen übrigens nochmals Klammern gesetzt
werden, damit die Termberechnung nach entferntem Adressierungsmerkmal nicht
durcheinander gerät:
JMP ((2312+42)-(3+2))
Fehler, die scheinbar in Makroquelltexten auftreten, müssen nicht immer
am Makroquelltext liegen. Oftmals ist ein falscher Übergabeparameter
schuld. Übergabeparameter können intensive Auswirkungen haben, sie bestim-
men teilweise sogar die Adressierungsart von Mnemonics. Als Beispiel sei
die einfache Zeile "lda ?0,y" dienen. Wird ein 8-Bit-Übergabeparameter
übergeben, bricht der Assembler ab, da das LDA-Mnemonic keine
Zeropage-y-indizierte Adressierung kennt. Abhilfe: "lda !?0,y".
Mit dem 6510-Developers-Packet Programme für andere Rechner mit dem 6510
zu entwickeln dürfte keine große Schwierigkeit sein. Besonders einfach ist
dies natürlich für den großen Bruder des C64, den C128 zu realisieren, da
dieser ja über den C64-Modus verfügt. Programme für ihn werden mit
CrossAss assembliert, im C64-Modus übertragen und auf Disk gespeichert und
im 128-Modus dann geladen und gestartet. Für andere Rechner (Atari
800XL/130XE, Apple II, alte CBM-Rechner etc.) müsste sowohl eine Hard-
waregrundlage (Übertragungskabel) als auch eine Empfangsroutine geschrieben
werden, um mit dem 6510-Developers-Packet arbeiten zu können. Vielleicht
findet auch hier jemand Möglichkeiten.
Zum Schluß bleibt mir nur noch zu hoffen, daß das 6510-Developers-Packet
für viele Programmierer ein nützliches Werkzeug wird, das ihre Arbeit
erleichtert.
Einige Begriffserläuterungen:
ASSEMBLIERUNG / ASSEMBLER:
Genaueres unter -> Quelltext.
LABEL (= Symbol):
Alphanumerische Zeichenkette, die im -> Quelltext einen ihr zugewiesenen
Wert vertritt. Der Labelname muß mit einem Buchstaben beginnen und darf
bis zu 32 Zeichen lang sein, wobei dann auch Ziffern und das Zeichen "_" im
Namen enthalten sein dürfen. Die Wertzuweisung erfolgt entweder explizit
per -> Pseudo-Opcode ".equal" oder durch Angabe am Zeilenanfang. In
letzterem Fall wird dem Label der aktuelle Wert des -> Programmcounters
zugewiesen. Die Groß- und Kleinschreibung wird bei Labels beachtet, so daß
sowohl ein Label "Marke" als auch ein Label "marke" oder "MARKE" existieren
kann, die alle unterschiedliche Werte repräsentieren.
MAKRO:
Alphanumerische Zeichenkette, die im Quelltext einen ihm zugewiesenen
Makroquelltext vertritt. Das Makro wird mit den Pseudo-Opcodes ".macro"
und ".endmacro" definiert. Zur Namensgebung gelten dieselben Regeln wie
bei Labeldefinitionen. Das Makro kann je nach Definition bis zu 10 Über-
gabeparameter erhalten, die nur innerhalb des Makroquelltextes bekannt
sind. Innerhalb eines Makros definierte -> Labels gelten als lokale Labels
und sind nur innerhalb des Makroquelltextes bekannt.
MNEMONIC:
Mnemonic ist die Bezeichnung für alle standarisierten Befehlskürzel zur
Vertretung von Maschinensprachbefehlen (-> Opcodes). Da die Programmierung
rein durch Zahlen oder gar Bitfolgen wohl alles andere als einfach wäre,
bekommen die einzelnen Befehle Namen, eben die Mnemonics. CrossAss hält
sich genau an den Standard des 6510, der von anderen Assemblern bekannt
ist. Jedes Mnemonic ist genau drei Zeichen lang. Mnemonics sind nicht
"case sensitiv"; es ist also egal, ob Mnemonics groß, klein oder gemischt
geschrieben werden.
OBJEKTCODE (= Objektprogramm):
Die entgültige Bitfolge (oder besser Bytefolge), die das tatsächliche,
vom Prozessor verständliche Programm darstellt. Um diese erzeugen zu
können benötigt man eben den Assembler.
OPCODE (= Operationscode):
Ein Mikroprozessor wie der 6510 des C64 versteht eigentlich nur
Bitfolgen. Acht solcher Bits zusammen kennzeichnen einen bestimmte
Funktion des Prozessors, die dieser ausführt, wenn er bei der Abarbeitung
auf diese Bitfolge stößt. Ein Opcode ist also nichts anderes als eine
8-Bit-Zahl, die einen solchen Befehl darstellt.
PSEUDO-OPCODE (= Pseudoinstruktion, Direktive):
Pseudo-Opcodes sind Anweisungen, die im Gegensatz zu -> Mnemonics den ->
Assembler selbst etwas tun lassen und damit die -> Assemblierung an sich
beeinflussen. Die Aufgaben der einzelnen Pseudo-Opcodes variieren sehr
stark und sind deshalb in der Anleitung einzeln beschrieben.
QUELLTEXT (= Quellcode, Quellprogramm, Sourcecode):
Ein 6510-Assembler-Programm als ASCII-Textdatei. Um dieses Programm
ausführen zu können, muß es erst in die für den Prozessor verständliche
Bitfolge (-> Opcodes) umgewandelt werden. Diesen Vorgang nennt man
"Assemblierung", das Programm, das diese Arbeit erledigt ist der
"Assembler".